﻿/*========================== 
 * @author 郑金泉
 * @desc MVC 视图
 * ========================= */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.SessionState;
using System.Web;
using System.IO;
using System.Threading;

using Obsidian.Utils;
using Obsidian.Runtime;
using Obsidian.Web;
using Obsidian.Config;

namespace Obsidian.Mvc
{
    public class OView
    {

        private const string PN_VIEW = "__vid__";
        private const string SKN_VIEWS = "__views__";
        private const string VIEW_PATH_COMMENT = "\r\n<!-- #VIEW:{0} {1} -->\r\n";
        private string _path;
        private Dictionary<string, object> _datas = new Dictionary<string, object>();

        public string Path
        {
            get { return this._path; }
        }

        public OView(string path)
        {
            this._path = path;
        }

        public object GetData(string key)
        {
            return this._datas[key];
        }

        public void SetData(string key, object val)
        {
            this._datas[key] = val;
        }

        public bool TryGetData<T>(string key, out T o)
        {
            object d;
            if(!this._datas.TryGetValue(key, out d))
            {
                o = default(T);
                return false;
            }
            if (d == null)
            {
                o = default(T);
                return false;
            }
            try
            {
                o = (T)d;
                return true;
            }
            catch
            {
                o = default(T);
                return false;
            }
        }

        private static Dictionary<string, OView> GetSessionViews()
        {
            HttpSessionState session = HttpContext.Current.Session;
            Dictionary<string, OView> dict = (Dictionary<string, OView>)session[SKN_VIEWS];
            if (dict == null)
            {
                dict = new Dictionary<string, OView>();
                session[SKN_VIEWS] = dict;
            }
            return dict;
        }

        internal static void RemoveSessionViews()
        {
            Dictionary<string, OView> dict = GetSessionViews();
            dict.Clear();
            HttpContext.Current.Session.Remove(SKN_VIEWS);
        }

        public static OView CurrentView
        {
            get
            {
                string vid;
                if (ParamsReceiver.TryGetQueryString(PN_VIEW, out vid))
                {
                    Dictionary<string, OView> dict = GetSessionViews();
                    OView view;
                    if (!dict.TryGetValue(vid, out view))
                        return null;
                    return view;
                }
                return null;
            }
        }

        public void Display()
        {
            HttpContext context = HttpContext.Current;
            HttpRequest request = context.Request;
            HttpResponse response = context.Response;

            MvcConfig.MvcViewInfo configView = MvcConfig.ViewInfo;
            string home = configView.Home;
            if (StringUtil.Last(home, 1) != "/")
                home = home + "/";
            string path = home + this.Path + configView.Suffix;
            string vid = Guid.NewGuid().ToString();

            Dictionary<string, OView> dict = GetSessionViews();
            lock (dict)
                dict[vid] = this;

            string url = request.Url.ToString().ToLower();
            int qIndex = url.IndexOf("?");
            StringBuilder sbUrl = new StringBuilder();
            sbUrl.Append(path);
            if (qIndex > 0)
            {
                sbUrl.Append(url.Substring(qIndex));
                sbUrl.Append("&");
            }
            else
                sbUrl.Append("?");

            sbUrl.Append(PN_VIEW).Append("=").Append(vid);
            string viewUrl = sbUrl.ToString();

            /*
            HttpContext.Current.Response.Write(viewUrl);
            string str = viewUrl.Substring(0, viewUrl.IndexOf("?"));
            string filePath = HttpContext.Current.Server.MapPath(str);
            if (!File.Exists(filePath))
            {
                throw new Exception(String.Format("文件：{0}不存在", filePath));
            }
             * */

            if (AppConfig.IsDebug)
            {
                //response.Write(String.Format(VIEW_PATH_COMMENT, this._path, "start"));
                HttpContext.Current.Server.Execute(viewUrl);
                //response.Write(String.Format(VIEW_PATH_COMMENT, this._path, "end"));
            }
            else
            {
                try
                {
                    //response.Write(String.Format(VIEW_PATH_COMMENT, this._path, "start"));
                    HttpContext.Current.Server.Execute(viewUrl);
                    //response.Write(String.Format(VIEW_PATH_COMMENT, this._path, "end"));
                }
                catch (Exception ex)
                {
                    this.ProcessViewException(ex, viewUrl);
                }
            }
        }

        private void ProcessViewException(Exception ex, string viewUrl)
        {
            HttpContext context = HttpContext.Current;

            StringBuilder sbError = new StringBuilder();
            sbError.AppendLine("URL： " + context.Request.RawUrl);
            sbError.AppendLine("视图异常： " + viewUrl);

            string errorMsg = sbError.ToString();
            string errorCode = Logger.Error(ex, errorMsg);

            if (ErrorPage.Has(ErrorPage.StatusCode.Status500))
            {
                Dictionary<string, object> dict = new Dictionary<string, object>();
                dict["code"] = errorCode;
                ErrorPage.Redirect(ErrorPage.StatusCode.Status500, dict);
            }
            else
            {
                HttpResponse response = context.Response;
                response.Write("程序异常：" + errorCode);
            }
        }

    }
}
